﻿using Microsoft.Win32;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.Mail;
using System.Security.AccessControl;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 监控
{
    public partial class FormProc : Form
    {
        const int WM_HOTKEY = 0x0312;
        Configuration setting = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        
        public FormProc()
        {
            try
            {
                InitializeComponent();
                checkedListBox1.ContextMenuStrip = contextMenuStrip1;
                contextMenuStrip1.Tag = checkedListBox1;
                checkedListBox1.AllowDrop = true;
                checkedListBox1.DragEnter += CheckedListBox1_DragEnter;
                checkedListBox1.DragDrop += CheckedListBox1_DragDrop;
                checkedListBox1.Tag = new Dictionary<string, bool>();
                FormClosing += FormProc_FormClosing;

                contextMenuStrip1.Opened += ContextMenuStrip1_Opened;
                contextMenuStrip1.ItemClicked += ContextMenuStrip1_ItemClicked;
                for (int i = 0; i < setting.AppSettings.Settings.Count; i++)
                {
                    if (setting.AppSettings.Settings.AllKeys[i] != "starttime" && setting.AppSettings.Settings.AllKeys[i] != "key" && !setting.AppSettings.Settings.AllKeys[i].StartsWith("mail@"))
                    {
                        string[] data = setting.AppSettings.Settings[setting.AppSettings.Settings.AllKeys[i]].Value.Split(new char[] {','});
                        if (data.Length < 2) continue;
                        checkedListBox1.Items.Add(data.First());
                        checkedListBox1.SetItemChecked(checkedListBox1.Items.Count - 1, true);
                        (checkedListBox1.Tag as Dictionary<string, bool>).Add(checkedListBox1.Items[checkedListBox1.Items.Count - 1] as string,
                            int.Parse(data[1]) == 0 ? false : true);
                    }
                }

                InitHotKey();
                textBox1.KeyDown += TextBox1_KeyDown;
                textBox2.KeyDown += TextBox1_KeyDown;
                this.checkBox1.Checked = (Program.IsAutoStart() ? true : false);
                this.checkBox1.CheckedChanged += CheckBox1_CheckedChanged;
                this.Load += FormProc_Load;

                int iStartTime = 0;
                int.TryParse(setting.AppSettings.Settings["starttime"].Value, out iStartTime);
                numericUpDown1.Value = iStartTime;
                numericUpDown1.ValueChanged += NumericUpDown1_ValueChanged;
                //运行监控
                Task.Run(new Action(() =>
                {
                    Thread.Sleep(iStartTime * 1000);
                    Task.Run(new Action(() =>
                    {
                        while (true)
                        {
                            try
                            {
                                lock (setting)
                                {
                                    List<string> fileNoneExsist = new List<string>();
                                    for (int index = 0; index < checkedListBox1.Items.Count; index++)
                                    {
                                        //未启动程序监控
                                        string item = checkedListBox1.Items[index] as string;
                                        if (checkedListBox1.GetItemChecked(index) == true && Process.GetProcessesByName(Path.GetFileNameWithoutExtension(item))
                                            .Where(o=> GetProcessUserName(o.Id)==Environment.UserName||GetProcessUserName(o.Id)=="").ToArray().Length == 0)
                                        {
                                            if (File.Exists(item))
                                            {
                                                ProcessStartInfo startInfo = new ProcessStartInfo();
                                                startInfo.FileName = item;
                                                startInfo.WorkingDirectory = Path.GetDirectoryName(item);
                                                Process.Start(startInfo);
                                                if (!Directory.Exists("log")) Directory.CreateDirectory("log");
                                                File.AppendAllLines("./log/" + DateTime.Now.ToString("yyyyMMdd") + ".log", new string[] {
                                                DateTime.Now+"  start "+ item });
                                                if (setting.AppSettings.Settings.AllKeys.Contains("mail@" + Path.GetFileName(item)))
                                                {
                                                    FormUser user = new FormUser(setting.AppSettings.Settings["mail@" + Path.GetFileName(item)].Value);
                                                    user.SendEmail(Path.GetFileNameWithoutExtension(item), item);
                                                }
                                            }
                                            else
                                            {
                                                fileNoneExsist.Add(item);
                                            }
                                        }
                                    }
                                    //删除不存在文件
                                    foreach (string file in fileNoneExsist)
                                    {
                                        setting.AppSettings.Settings.Remove(file);
                                        setting.Save();
                                        checkedListBox1.Invoke(new Action(() =>
                                        {
                                            checkedListBox1.Items.Remove(setting.AppSettings.Settings[file].Value);
                                        }));
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                if (!Directory.Exists("log")) Directory.CreateDirectory("log");
                                File.AppendAllLines("./log/" + DateTime.Now.ToString("yyyyMMdd") + ".log", new string[] {
                                    DateTime.Now+"  "+ex.Message });
                            }
                            Thread.Sleep(1000);
                        }
                    }));
                }));
                //进程监控
                Task.Run(new Action(() =>
                {
                    while (true)
                    {
                        try
                        {
                            for (int index = 0; index < checkedListBox1.Items.Count; index++)
                            {
                                bool bCheck = false;
                                string objSelectItem = "";
                                string item = checkedListBox1.Items[index] as string;
                                checkedListBox1.Invoke(new Action(() =>
                                {
                                    bCheck = checkedListBox1.GetItemChecked(index);
                                    objSelectItem = checkedListBox1.Items[index] as string;
                                }));
                                //运行程序监控
                                if (bCheck == true && objSelectItem != null &&
                                        Process.GetProcessesByName(Path.GetFileNameWithoutExtension(item)).Length > 0 &&
                                        (checkedListBox1.Tag as Dictionary<string, bool>).ContainsKey(item) &&
                                        (checkedListBox1.Tag as Dictionary<string, bool>)[item] == true)
                                {
                                    Process.GetProcessesByName(Path.GetFileNameWithoutExtension(objSelectItem)).
                                        Concat(Process.GetProcessesByName("WerFault")).
                                        Concat(Process.GetProcessesByName("csrss")).
                                        ToList().ForEach(o =>
                                        {
                                            if (o.ProcessName == Path.GetFileName(objSelectItem) ||
                                                o.MainWindowTitle == "Microsoft Visual C++ Runtime Library" ||
                                                o.MainWindowTitle == "Microsoft Visual C++ Debug Library" ||
                                                o.MainWindowTitle == "Microsoft Visual Studio" ||
                                                o.MainWindowTitle.EndsWith("- 系统错误") ||
                                                o.MainWindowTitle.EndsWith("- 应用程序错误")
                                                )
                                            {
                                                try
                                                {
                                                    if (!Directory.Exists("log")) Directory.CreateDirectory("log");
                                                    File.AppendAllLines("./log/" + DateTime.Now.ToString("yyyyMMdd") + ".log", new string[] {
                                                        DateTime.Now+"  "+o.ProcessName+"弹出错误窗口【"+o.MainWindowTitle+"】" });
                                                    Program.SendMessageTimeout(o.MainWindowHandle, Program.WM_CLOSE, IntPtr.Zero, IntPtr.Zero, 0, 1000, IntPtr.Zero);
                                                    Task.Factory.StartNew(new Action<object>(t => { 
                                                        Thread.Sleep(1000);//窗口无法关闭，强制退出
                                                        if (!((Process)t).HasExited)
                                                            ((Process)t).Kill();
                                                    }),o);
                                                }
                                                catch { }
                                            }
                                            else
                                            {
                                                if (o.MainWindowHandle != IntPtr.Zero && o.MainWindowTitle.Contains(Path.GetFileName(objSelectItem)))
                                                    Program.SendMessageTimeout(o.MainWindowHandle, Program.WM_CLOSE, IntPtr.Zero, IntPtr.Zero, 0, 1000, IntPtr.Zero);
                                                Thread.Sleep(3000);
                                            }
                                        });
                                }
                            }
                            Thread.Sleep(1000);
                        }
                        catch { }
                    }
                }));
            }
            catch(Exception ee) {
                TopMost = false;
                MessageBox.Show(MessageboxExtension.CloseAfter(3000), ee.Message);
                TopMost = true;
            }
        }
        private void CheckedListBox1_DragDrop(object sender, DragEventArgs e)
        {
            foreach (string item in ((Array)e.Data.GetData(DataFormats.FileDrop))?.Cast<string>())
            {
                string filePath = item;
                if (Path.GetExtension(item) == ".lnk")
                    filePath = ((IWshRuntimeLibrary.IWshShortcut)(new IWshRuntimeLibrary.WshShell().CreateShortcut(item))).TargetPath;
                else if (Path.GetExtension(item) != ".exe")
                    continue;

                string file = Path.GetFileName(filePath);
                if (!setting.AppSettings.Settings.AllKeys.Contains(file))
                {
                    checkedListBox1.Items.Add(filePath);
                    checkedListBox1.SetItemChecked(checkedListBox1.Items.Count - 1, true);
                    (checkedListBox1.Tag as Dictionary<string, bool>).Add(filePath, false);
                    lock (setting)
                    {
                        setting.AppSettings.Settings.Add(file, filePath + ",0");
                        setting.Save();
                    }
                }
            }
        }
        private void CheckedListBox1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ?
                DragDropEffects.All : DragDropEffects.None;
        }
        private static string GetProcessUserName(int pID)
        {
            SelectQuery query = new SelectQuery("Select * from Win32_Process WHERE processID=" + pID);
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
            try
            {
                foreach (ManagementObject disk in searcher.Get())
                {
                    ManagementBaseObject outPar = disk.InvokeMethod("GetOwner", disk.GetMethodParameters("GetOwner"), null); ;
                    return outPar["User"].ToString();
                }
                return "";
            }
            catch
            {
                return "";
            }
        }
        private void ContextMenuStrip1_Opened(object sender, EventArgs e)
        {
            try
            {
                Point pt = checkedListBox1.PointToClient(MousePosition);
                checkedListBox1.SelectedIndex = checkedListBox1.IndexFromPoint(pt);
                if (checkedListBox1.SelectedIndex == -1) return;
                //邮件
                (contextMenuStrip1.Items[7] as ToolStripMenuItem).Checked =
                    setting.AppSettings.Settings.AllKeys.Contains("mail@" + Path.GetFileName(checkedListBox1.SelectedItem as string));
                //监控
                (contextMenuStrip1.Items[8] as ToolStripMenuItem).Checked =
                    (checkedListBox1.Tag as Dictionary<string, bool>)[checkedListBox1.SelectedItem as string];
            }
            catch { }
        }
        private void NumericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            try{
                setting.AppSettings.Settings.Remove("starttime");
                setting.AppSettings.Settings.Add("starttime", numericUpDown1.Value.ToString());
                setting.Save();
            }
            catch { }
        }
        ~FormProc()
        {
            HotKeyManager.UnregisterHotKey(Handle, 100);
        }
        void InitHotKey()
        {
            if (setting.AppSettings.Settings.AllKeys.Contains("key"))
            {
                try
                {
                    Keys key1, key2;
                    string[] keys = setting.AppSettings.Settings["key"].Value.Split(new char[] { '_' });
                    Enum.TryParse(keys[0], out key1);
                    Enum.TryParse(keys[1], out key2);
                    HotKeyManager.RegisterHotKey(Handle, 100, KeyConvert(key2), key1);
                    textBox2.Text = keys[1];
                    textBox1.Text = keys[0];
                }
                catch { }
            }
        }
        KeyModifiers KeyConvert(Keys key)
        {
            switch (key)
            {
                case Keys.Alt: return KeyModifiers.Alt; 
                case Keys.ShiftKey: return KeyModifiers.Shift;
                case Keys.Shift: return KeyModifiers.Shift;
                case Keys.ControlKey: return KeyModifiers.Ctrl;
                case Keys.Control: return KeyModifiers.Ctrl;
                case Keys.LWin: return KeyModifiers.WindowsKey;
                case Keys.RWin: return KeyModifiers.WindowsKey;
                default: return KeyModifiers.None;
            }
        }
        private void TextBox1_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if (e.KeyCode != Keys.ControlKey && e.KeyCode != Keys.Alt && e.KeyCode != Keys.ShiftKey)
                {
                    textBox1.Text = e.KeyCode.ToString();
                    HotKeyManager.UnregisterHotKey(Handle, 100);
                    HotKeyManager.RegisterHotKey(Handle, 100, KeyConvert(e.Modifiers), e.KeyCode);
                }
                textBox2.Text = e.Modifiers.ToString();
                if (setting.AppSettings.Settings.AllKeys.Contains("key"))
                    setting.AppSettings.Settings.Remove("key");

                setting.AppSettings.Settings.Add("key", textBox1.Text + "_" + textBox2.Text);
                setting.Save();
            }
            catch(Exception ex) {
                TopMost = false;
                MessageBox.Show(MessageboxExtension.CloseAfter(3000),ex.Message);
                TopMost = true;
            }
        }
        private void CheckBox1_CheckedChanged(object sender, EventArgs e)
        {
            this.checkBox1.CheckedChanged -= CheckBox1_CheckedChanged;
            bool ret = Program.RegistryAutoStart(checkBox1.Checked);
            if (!ret){
                TopMost = false;
                MessageBox.Show(MessageboxExtension.CloseAfter(3000), "需要管理员权限");
                TopMost = true;
            }
            checkBox1.Checked = (ret && checkBox1.Checked);
            this.checkBox1.CheckedChanged += CheckBox1_CheckedChanged;
        }
        private void FormProc_Load(object sender, EventArgs e)
        {
            Hide();
        }
        private void FormProc_FormClosing(object sender, FormClosingEventArgs e)
        {
            Visible = false;
            e.Cancel = true;
        }
        private void ContextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            try
            {
                ContextMenuStrip menu = sender as ContextMenuStrip;
                switch (menu.Items.IndexOf(e.ClickedItem))
                {
                    case 0:
                        {
                            menu.Visible = false;
                            OpenFileDialog flDlg = new OpenFileDialog() { Filter = "应用程序|*.exe|所有文件|*.*" };
                            if (flDlg.ShowDialog() == DialogResult.OK)
                            {
                                if (!setting.AppSettings.Settings.AllKeys.Contains(flDlg.SafeFileName))
                                {
                                    checkedListBox1.Items.Add(flDlg.FileName);
                                    checkedListBox1.SetItemChecked(checkedListBox1.Items.Count - 1, true);
                                    (checkedListBox1.Tag as Dictionary<string,bool>).Add(flDlg.FileName, false);
                                    lock (setting)
                                    {
                                        setting.AppSettings.Settings.Add(flDlg.SafeFileName, flDlg.FileName+",0");
                                        setting.Save();
                                    }
                                }
                            }
                            break;
                        }
                    case 1:
                        {
                            if (checkedListBox1.Items.Count > 0 && checkedListBox1.SelectedIndex >= 0)
                            {
                                lock (setting)
                                {
                                    setting.AppSettings.Settings.Remove(Path.GetFileName(checkedListBox1.SelectedItem as string));
                                    (checkedListBox1.Tag as Dictionary<string, bool>).Remove(checkedListBox1.SelectedItem as string);
                                    setting.Save();
                                }
                                checkedListBox1.Items.RemoveAt(checkedListBox1.SelectedIndex);
                            }
                            break;
                        }
                    case 2:break;//分隔符
                    case 3:
                        {
                            if (checkedListBox1.SelectedIndex >= 0)
                            {
                                checkedListBox1.SetItemChecked(checkedListBox1.SelectedIndex, false);
                                Process.GetProcessesByName(Path.GetFileNameWithoutExtension(checkedListBox1.SelectedItem as string)).
                                    ToList().ForEach(o => o.Kill());
                            }
                            break;
                        }
                    case 4:
                        {//重启
                            if (checkedListBox1.SelectedIndex >= 0)
                            {
                                checkedListBox1.SetItemChecked(checkedListBox1.SelectedIndex, true);
                                Process.GetProcessesByName(Path.GetFileNameWithoutExtension(checkedListBox1.SelectedItem as string)).
                                    ToList().ForEach(o => o.Kill());
                            }
                            break;
                        }
                    case 5:break;//分隔符
                    case 6:
                        {
                            try{
                                if(checkedListBox1.SelectedIndex >= 0)
                                    Process.Start("explorer.exe", Path.GetDirectoryName(checkedListBox1.SelectedItem as string));
                            }
                            catch { }
                            break;
                        }
                    case 7:
                        {//邮件
                            if (checkedListBox1.Items.Count > 0 && checkedListBox1.SelectedIndex >= 0)
                            {
                                string config = null;
                                lock (setting)
                                {
                                    if (setting.AppSettings.Settings.AllKeys.Contains("mail@" + Path.GetFileName(checkedListBox1.SelectedItem as string)))
                                        config = setting.AppSettings.Settings["mail@" + Path.GetFileName(checkedListBox1.SelectedItem as string)].Value;
                                }
                                //打开窗口
                                FormUser user = new FormUser(config);
                                TopMost = false;
                                user.ShowDialog();
                                TopMost = true;
                                lock (setting)
                                {
                                    if (setting.AppSettings.Settings.AllKeys.Contains("mail@" + Path.GetFileName(checkedListBox1.SelectedItem as string)))
                                        setting.AppSettings.Settings.Remove("mail@" + Path.GetFileName(checkedListBox1.SelectedItem as string));
                                    if (user.IsSet)
                                        setting.AppSettings.Settings.Add("mail@" + Path.GetFileName(checkedListBox1.SelectedItem as string), user.saveData);
                                    setting.Save();
                                }
                            }
                            break;
                        }
                    case 8:
                        {//监控
                            int index = menu.Items.IndexOf(e.ClickedItem);
                            if (checkedListBox1.SelectedItem != null && (checkedListBox1.Tag as Dictionary<string, bool>).ContainsKey(checkedListBox1.SelectedItem as string))
                            {
                                (menu.Items[index] as ToolStripMenuItem).Checked = !(menu.Items[index] as ToolStripMenuItem).Checked;
                                (checkedListBox1.Tag as Dictionary<string, bool>)[checkedListBox1.SelectedItem as string] = (menu.Items[index] as ToolStripMenuItem).Checked;
                                lock (setting)
                                {
                                    setting.AppSettings.Settings.Remove(Path.GetFileName(checkedListBox1.SelectedItem as string));
                                    setting.AppSettings.Settings.Add(Path.GetFileName(checkedListBox1.SelectedItem as string), (checkedListBox1.SelectedItem as string) + ","+ 
                                        ((menu.Items[index] as ToolStripMenuItem).Checked?1:0));
                                    setting.Save();
                                }
                            }
                            break;
                        }
                    case 10:
                        {
                            int index = menu.Items.IndexOf(e.ClickedItem);
                            (menu.Items[index] as ToolStripMenuItem).Checked = !(menu.Items[index] as ToolStripMenuItem).Checked;
                            TopMost = (menu.Items[index] as ToolStripMenuItem).Checked?true:false;
                            break;
                        }
                    default:break;
                }
                menu.Visible = true;
            }
            catch (Exception ex) {
                contextMenuStrip1.Visible = true;
                TopMost = false;
                MessageBox.Show(MessageboxExtension.CloseAfter(3000),ex.Message);
                TopMost = true;
            }
        }
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_HOTKEY:
                    switch (m.WParam.ToInt32())
                    {
                        case 100:
                            if (!Visible)
                            {
                                Visible = true;
                                WindowState = FormWindowState.Normal;
                                Show();
                            }
                            break;
                    }
                    break;
            }
            base.WndProc(ref m);
        }
    }
}
